package com.cicadasmall.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cicadasmall.common.base.BaseService;
import com.cicadasmall.common.constant.Constant;
import com.cicadasmall.common.exception.ServiceException;
import com.cicadasmall.common.func.Fn;
import com.cicadasmall.common.resp.R;
import com.cicadasmall.system.dto.RoleInputDTO;
import com.cicadasmall.system.dto.RoleQueryDTO;
import com.cicadasmall.system.dto.RoleUpdateDTO;
import com.cicadasmall.data.domain.MenuDO;
import com.cicadasmall.data.domain.RoleDO;
import com.cicadasmall.system.service.IMenuService;
import com.cicadasmall.system.service.IRoleMenuService;
import com.cicadasmall.system.service.IRoleService;
import com.cicadasmall.system.vo.RoleVO;
import com.cicadasmall.data.mapper.SysRoleMapper;
import com.cicadasmall.system.wrapper.RoleWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author westboy
 * @date 2019-07-10
 */
@Service
public class RoleServiceImpl extends BaseService<SysRoleMapper, RoleDO> implements IRoleService {
    @Autowired
    private IRoleMenuService roleMenuService;
    @Autowired
    private IMenuService menuService;

    @Override
    public List<RoleDO> findByUserId(Serializable userId) {
        return baseMapper.selectByUserId(userId);
    }

    @Override
    public List<RoleVO> getTree() {
        return RoleWrapper.newBuilder().treeVO(this.findAll());
    }

    @Override
    public List<RoleVO> findList(RoleQueryDTO roleQueryDTO) {

        LambdaQueryWrapper<RoleDO> lambdaQueryWrapper = getLambdaQueryWrapper();

        if (Fn.isNotNull(roleQueryDTO.getParentId())) {
            lambdaQueryWrapper.eq(RoleDO::getParentId, roleQueryDTO.getParentId());
        }

        List<RoleDO> roleList = baseMapper.selectList(lambdaQueryWrapper);

        return RoleWrapper.newBuilder().listVO(roleList);
    }


    @Override
    public R page(RoleQueryDTO roleQueryDTO) {
        RoleDO role = roleQueryDTO.convertToEntity();
        Page page = baseMapper.selectPage(roleQueryDTO.page(), getLambdaQueryWrapper().setEntity(role));
        return R.ok(RoleWrapper.newBuilder().pageVO(page));
    }

    @Override
    public R save(RoleInputDTO roleInputDTO) {
        RoleDO role = roleInputDTO.convertToEntity();
        checkAndSave(role);
        roleMenuService.updateRoleMenu(role.getRoleId(), roleInputDTO.getPermissionIdList());
        return R.ok(true);
    }

    private void checkAndSave(RoleDO role) {
        RoleDO parentRole = null;

        if (Fn.isNotNull(role.getParentId()) && Fn.notEqual(Constant.PARENT_ID, role.getParentId())) {
            parentRole = getById(role.getParentId());
            if (parentRole == null) {
                throw new ServiceException("上级J角色选择有误！");
            }
        } else {
            role.setParentId(Constant.PARENT_ID);
        }

        save(role);

        //更新上级角色
        if (parentRole != null) {
            parentRole.setHasChildren(true);
            updateById(parentRole);
        }

    }

    @Override
    public R update(RoleUpdateDTO roleUpdateDTO) {
        RoleDO role = roleUpdateDTO.convertToEntity();
        checkAndUpdate(role);
        roleMenuService.updateRoleMenu(role.getRoleId(), roleUpdateDTO.getPermissionIds());
        return R.ok(true);
    }

    public List<RoleDO> findByParentId(Serializable parentId) {
        LambdaQueryWrapper<RoleDO> lambdaQueryWrapper = getLambdaQueryWrapper();
        lambdaQueryWrapper.eq(RoleDO::getParentId, parentId);
        return baseMapper.selectList(lambdaQueryWrapper);
    }

    private void checkAndUpdate(RoleDO role) {

        RoleDO currentRole = getById(role.getRoleId());

        if (Fn.isNull(currentRole)) {
            throw new ServiceException("参数错误！");
        }

        if (Fn.equal(role.getParentId(), currentRole.getRoleId())) {
            throw new ServiceException("上级部门不能为当前部门！");
        }

        List<RoleDO> currentRoleChildList = findByParentId(currentRole.getRoleId());

        if (Fn.isNotNull(role.getParentId()) && Fn.notEqual(Constant.PARENT_ID, role.getParentId()) && Fn.notEqual(role.getParentId(), currentRole.getParentId())) {

            RoleDO currentParentRole = getById(role.getParentId());

            if (Fn.isNull(currentParentRole)) {
                throw new ServiceException("上级部门不存在！");
            }

            if (CollectionUtil.isNotEmpty(currentRoleChildList)) {
                AtomicReference<Boolean> error = new AtomicReference<>(false);
                currentRoleChildList.parallelStream().forEach(e -> error.set(e.getRoleId().equals(currentParentRole.getRoleId())));
                if (error.get()) {
                    throw new ServiceException("上级部门选择有误！");
                }
            }

            currentParentRole.setHasChildren(true);
            updateById(currentParentRole);

        }

        //Jin 判断当前是否拥有下级
        role.setHasChildren(Fn.isNotEmpty(currentRoleChildList));

        updateById(role);

        RoleDO quondamParentRole = getById(currentRole.getParentId());
        if (Fn.isNotNull(quondamParentRole)) {
            List<RoleDO> parentDeptChildList = findByParentId(currentRole.getParentId());
            if (CollectionUtil.isEmpty(parentDeptChildList)) {
                quondamParentRole.setHasChildren(false);
                updateById(quondamParentRole);
            }
        }
    }

    @Override
    public R<RoleVO> findById(Serializable id) {
        RoleDO role = baseMapper.selectById(id);
        if (Fn.isNull(role)) {
            throw new ServiceException("角色不存在！");
        }
        RoleVO roleVo = RoleWrapper.newBuilder().entityVO(role);
        List<MenuDO> menuList = menuService.findByRoleId(roleVo.getRoleId());
        //设置选中的权限
        if (Fn.isNotEmpty(menuList)) {
            List<Integer> menuIds = menuList.stream().map(MenuDO::getMenuId).collect(Collectors.toList());
            roleVo.setSelectedPermissionIds(menuIds.toArray(new Integer[menuIds.size()]));
        } else {
            roleVo.setSelectedPermissionIds(new Integer[]{});
        }
        return R.ok(roleVo);
    }

    @Override
    public R deleteById(Serializable id) {
        LambdaQueryWrapper<RoleDO> queryWrapper = getLambdaQueryWrapper().eq(RoleDO::getParentId, id);
        Integer count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new ServiceException("请先删除子角色后再操作！");
        }

        RoleDO role = getById(id);

        if (Fn.isNull(role)) {
            throw new ServiceException("角色不存在！");
        }

        removeById(id);


        if (Fn.isNotNull(role.getParentId()) && Fn.notEqual(Constant.PARENT_ID, role.getParentId())) {
            Integer childCount = baseMapper.selectCount(getLambdaQueryWrapper().eq(RoleDO::getParentId, role.getParentId()));

            //更新上级菜单状态
            if (childCount <= 0) {
                RoleDO parentRole = getById(role.getParentId());
                parentRole.setHasChildren(false);
                updateById(parentRole);
            }
        }
        return R.ok(true);
    }

}
